


考虑JIT编译器时，首先想到的是直接运行LLVM IR。这就是lli工具、LLVM解释器和动态编译器所做的工作。我们将在下一节中探讨lli工具。


\mySubsubsection{9.3.1.}{探索lli工具}

让我们用一个非常简单的例子来试试lli工具。下面的LLVM IR可以存储为一个名为hello.ll的文件，相当于C语言中的hello world应用程序。该文件声明了来自C库的printf()函数的原型，hellostr常量包含要打印的消息。在main()函数内部，生成对printf()函数的调用，该函数包含将打印的hellostr消息，应用程序总是返回0。

完整的代码如下所示:

\begin{shell}
declare i32 @printf(ptr, ...)

@hellostr = private unnamed_addr constant [13 x i8] c"Hello
world\0A\00"

define dso_local i32 @main(i32 %argc, ptr %argv) {
    %res = call i32 (ptr, ...) @printf(ptr @hellostr)
    ret i32 0
}
\end{shell}

这个LLVM IR文件是通用的，对所有平台都有效。可以使用cli工具直接执行IR，命令如下:

\begin{shell}
$ lli hello.ll
Hello world
\end{shell}

这里有趣的一点是如何找到printf()函数。IR代码会编译为机器码，并触发printf符号的查找。这个符号在IR中找不到，所以在当前进程中搜索它，lli工具会动态链接到C库，在那里可以找到该符号。

当然，lli工具不会链接到创建的库。为了使用这些函数，lli工具支持加载动态库和对象。下面的C代码只输出消息:

\begin{shell}
#include <stdio.h>

void greetings() {
    puts("Hi!");
}
\end{shell}

存储在greetings.c中，使用它来探索用lli加载对象。下面的命令将把这个源代码编译成一个动态库，–fPIC选项指示clang生成与位置无关的代码，这是动态库所必需的。此外，编译器还会用-shared创建一个greetings.so动态库:

\begin{shell}
$ clang greetings.c -fPIC -shared -o greetings.so
\end{shell}

我们还将该文件编译为greetings.o对象文件:

\begin{shell}
$ clang greetings.c -c -o greetings.o
\end{shell}

现在有两个文件，greetings.so动态库和greetings.o对象文件，加载到lli工具中。

还需要一个调用greetings()函数的LLVM IR文件，还要创建一个main.ll文件，包含单个函数调用:

\begin{shell}
declare void @greetings(...)

define dso_local i32 @main(i32 %argc, i8** %argv) {
    call void (...) @greetings()
    ret i32 0
}
\end{shell}

执行时，因为lli无法定位greetings符号，所以前面的IR崩溃了，:

\begin{shell}
$ lli main.ll
JIT session error: Symbols not found: [ _greetings ]
lli: Failed to materialize symbols: { (main, { _main }) }
\end{shell}

greetings()函数是在一个外部文件中定义的，为了修复崩溃，必须告诉lli工具需要加载哪个文件。为了使用动态库，必须使用-load选项，该选项将动态库的路径作为参数:

\begin{shell}
$ lli –load ./greetings.so main.ll
Hi!
\end{shell}

若包含动态库的目录不在动态加载器的搜索路径中，则指定动态库的路径非常重要。若省略，则将找不到库。

或者，用-extra-object命令lli加载目标文件:

\begin{shell}
$ lli –extra-object greetings.o main.ll
Hi!
\end{shell}

其他支持的选项有-extra-archive(加载存档文件)和-extramodule(加载另一个位码文件)。这两个选项都需要文件的路径作为参数。

现在，了解了如何使用lli工具直接执行LLVM IR。下一节中，我们将实现自己的JIT工具。










